package com.rj.gpdata.domain;

import com.rj.gpdata.client.ApiFinanceClient;
import com.rj.gpdata.client.ApiKlineClient;
import com.rj.util.ForEachUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowCallbackHandler;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Consumer;

/**
 * 数据处理服务
 * Created by rj on 2017/9/5.
 */
@Component
@RequiredArgsConstructor
public class DataHandlerService {
    private  final JdbcTemplate jdbcTemplate;
    private final Map<String, String> fieldMapCache =Collections.synchronizedMap(new HashMap<>());
    private final Map<String, String> lock =Collections.synchronizedMap(new HashMap<>());
    private String createMysqlDataType(Object value){
        if(value == null){
            return "varchar(20)";
        }
        if(value instanceof Double){
            return "double";
        }
        if(value instanceof Float){
            return "float";
        }
        if(value instanceof Integer){
            return "int";
        }
        if(value instanceof Boolean){
            return "boolean";
        }
        if(value instanceof Long){
            return "bigint";
        }
        if(value instanceof Date){
            return "datetime";
        }
        return "varchar(20)";
    }

    private Object handlerValue(Object value){
        if(value == null || "-".equals(value)){
            return null;
        }
        return value;
    }
    /**
     * 数据查询处理
     * @param tableName
     * @param columnNames
     * @param callbackHandler
     */
    public void queryMainCodeData(String tableName, String columnNames, RowCallbackHandler callbackHandler){
         queryMainCodeData(tableName,columnNames,null,callbackHandler);
    }
    /**
     * 数据更新处理
     * @param tableName
     * @param setColumns
     * @param where
     */
    public boolean updateData(String tableName, String setColumns,String where){
        int update =jdbcTemplate.update("update %s set %s where %s".formatted(tableName,setColumns,where));
        return  update>0;
    }
    /**
     * 数据查询处理
     * @param tableName
     * @param columnNames
     * @param callbackHandler
     */
    public void queryMainCodeData(String tableName, String columnNames,String where, RowCallbackHandler callbackHandler){
        StringBuilder sql = new StringBuilder();
        sql.append("select ").append(columnNames).append(" from ").append(tableName);
        if(StringUtils.hasLength(where)){
            sql.append(" where ").append(where);
        }

        jdbcTemplate.query(sql.toString(),callbackHandler);
    }
   /**
     * 数据查询处理
     * @param securityCode
     * @param logType 0 主线数据 1主财务数据 2日K
     * @param atomicInteger
     */
    public void queryLogData(String securityCode, Integer logType, AtomicInteger atomicInteger){
        AtomicBoolean isExist = new AtomicBoolean(false);
        queryMainCodeData("syn_log","DATA_CT",
                "LOG_TYPE="+logType+" and SECURITY_CODE='"+securityCode+"'",(rs)-> {
                    Integer total = rs.getInt("DATA_CT");
                    atomicInteger.set(atomicInteger.get()-total);
                    if(!isExist.get()){
                        isExist.set(true);
                    }
                });
        if(!isExist.get()){
            jdbcTemplate.update("insert into syn_log(SECURITY_CODE,LOG_TYPE,DATA_CT,UPDATE_TIME) values('"+securityCode+"',"+logType+",0,now())");
        }
     }
    /**
     * 数据查询处理
     * @param securityCode
     * @param logType 0 主线数据 1主财务数据 2日K
     * @param totals
     */
    public void updateLogData(String securityCode, Integer logType, Integer totals){
          int update=jdbcTemplate.update("update  syn_log set data_ct="+totals+",update_time=now() where "+"LOG_TYPE="+logType+" and SECURITY_CODE='"+securityCode+"'");
          if(update == 0){
              jdbcTemplate.update("insert into syn_log(SECURITY_CODE,LOG_TYPE,DATA_CT,UPDATE_TIME) values('"+securityCode+"',"+logType+","+totals+",now())");
          }
    }
    /**
     * 数据保存处理
     * @param data
     */
    public void saveData(List<Map> data, String tableName) {
        if(data == null || data.size() == 0){
            System.out.println(tableName+"无数据需要保存");
            return;
        }
        synchronized (DataHandlerService.class){
            while (true){
                if(lock.containsKey(tableName)){
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                    }
                }else{
                    lock.put(tableName,"1");
                    break;
                }
            }

        }

        String mapColumnSqlCache = fieldMapCache.get(tableName);
        Map<String,String> fieldMap = new HashMap(30);
        if(mapColumnSqlCache == null){
            StringBuilder columnSql = new StringBuilder();
            //获取字段
            Set<Map.Entry<String,Object>> entrys = data.get(0).entrySet();
            ForEachUtils.exec(entrys,(entry, builder)-> {
                String key=entry.getKey();
                builder.append("`").append(key).append("`");
                //设置字段名、字段类型
                fieldMap.put(key,createMysqlDataType(entry.getValue()));
            }, columnSql,",");

            //1.检查数据库数据列
            //select COLUMN_Name from information_schema.COLUMNS t where t.table_schema='test' and table_name =''
            String sql = "select column_name from information_schema.COLUMNS t where t.table_schema='test' and table_name ='"+tableName+"' order by ORDINAL_POSITION asc";
            AtomicBoolean isExist = new AtomicBoolean(false);
            jdbcTemplate.query(sql,(rs)->{
                isExist.set(true);
                //2.对比接口字段，判断数据库列是否存在
                fieldMap.remove(rs.getString("COLUMN_NAME"));
            });

            if(!isExist.get()){
                //3.添加数据库表
                StringBuilder createSql = new StringBuilder();
                createSql.append("create table ").append(tableName).append("(");
                createSql.append("  `ID` int NOT NULL AUTO_INCREMENT COMMENT '编号',PRIMARY KEY (`ID`)");
                createSql.append(")");
                jdbcTemplate.execute(createSql.toString());
            }

            if(fieldMap.size()>0){
                //4.添加数据库行
                StringBuilder alterSql = new StringBuilder();
                alterSql.append("alter table ").append(tableName).append(" ");
                ForEachUtils.exec(fieldMap,(entry,builder)-> {
                    builder.append(" add column "+entry.getKey()+" "+entry.getValue()+"");
                }, alterSql,",");
                alterSql.append(";");
                //添加行信息
                jdbcTemplate.execute(alterSql.toString());
            }
            mapColumnSqlCache=columnSql.toString();
            fieldMapCache.put(tableName,mapColumnSqlCache);
        }
        lock.remove(tableName);
        //生成插入sql
        String insertMainSql="insert into "+tableName+"("+ mapColumnSqlCache +") values ";
        StringBuilder insertValueSql = new StringBuilder();
        ForEachUtils.exec(data, (map, insertBuilder)->{
            //拼接处理添加行信息
            insertBuilder.append("(");
            ForEachUtils.exec(map,(entry,b)->{
                Object entryValue = handlerValue(entry.getValue());
                if(entry.getValue()==null){
                    b.append("null");
                    return;
                }
                if(entryValue instanceof String){
                    b.append("'").append(entryValue).append("'");
                    return;
                }
                b.append(entryValue);
            },insertBuilder,",");
            insertBuilder.append(")");

        },insertValueSql, ",", (builder)->{
            //执行插入
            jdbcTemplate.execute(insertMainSql+builder.toString());
        },100);
    }
}
